'''A script designed to add several features that I thought were lacking 
from XChat, it's constantly evolving. Check individual modules for docs.'''
############################################################################
#    Copyright (C) 2006 by Robert Small                                    #
#    SmallR2002@Gmail.com                                                  #
#                                                                          #
#    This program is free software; you can redistribute it and#or modify  #
#    it under the terms of the GNU General Public License as published by  #
#    the Free Software Foundation; either version 2 of the License, or     #
#    (at your option) any later version.                                   #
#                                                                          #
#    This program is distributed in the hope that it will be useful,       #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#    GNU General Public License for more details.                          #
#                                                                          #
#    You should have received a copy of the GNU General Public License     #
#    along with this program; if not, write to the                         #
#    Free Software Foundation, Inc.,                                       #
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
############################################################################

#Script to add a few things I thought were needed in XChat

__module_name__        = "BottleCap"
__module_version__     = "0.0.6"
__module_release__     = "rc6"
__module_description__ = "A plugin to expand the features of IRC, for example, clones detection and CAPSLOCK protection. www.v8d.org/wiki/index.php?title=BottleCap"

#TODO: Build random quit message module.
#TODO: Build a user tracking module.
#TODO: Build a libpurple module.


# 
# 0.0.6  Just a few minor corrections here and there, a few minor additions to enable more
#       modules etc. A small change for the corrector module so that it handles first.
#       Many and various changes to make it more *correct*.
# 0.0.5	 This version is an attempt to split the whole lot into small manageable chunks, and
#       take all the misc junk out of the way... like the aol variable >.<
#       This led to an attempt at creating nix/win distinction in the plugin; debatable if it
#       will work as intended from the start - I need some windows PC's to test it on.
#       Incidentally, upgrade to the /samove /sacycle commands; takes 'this' channel if none
#       is specified. This should make things a little easier.
#       Modules now all have their own versions, discriptions, etc.
#
# 0.0.4	 This version includes some neat 'URL detection' code, which should mean that none of 
#       your URLs will be changed at all. Loads of new features, highlight response came
#       somewhere here. Also, automatic voicing/oping.
#
# 0.0.3  Auto away removed from engrish sub and into it's own, this means we can now have
#       the nice 'enable_correcting' without needing too much code. auto_away was also added
#       with little to no difficulty. Auto invite support is also added here, allows 'self',
#       'all' and 'list' based filtering of whom you accept the invite from.
#       Correction of case was set to be triggered only if there are more caps than lower case
#       this should cover the URL problems that were being had.
#
# 0.0.2  More advanced version, detected smilies and corrects them. Now handles Auto-Away.
# 
# 0.0.1  Basic test version, worked nicely.
# 

import xchat
import sys
import os, platform
import urllib2, urllib
import threading
import string #IGNORE:W0402

if (sys.path.count(os.path.dirname(__file__) + os.sep + "bottlecap") == 0):
    sys.path.append(os.path.dirname(__file__) + os.sep + "bottlecap")

#  No, don't remove the next line, bcsettings MUST be imported for this script to continue.
import bcsettings

if (hasattr(bcsettings, "not_read_config") == True):
    
    xchat.prnt("\x02\x0305ERROR: You have not read the settings file fully, BottleCap will NOT function until you have done so.\x03\x02")
else:
    def bcgeoip_load():
        import bcgeoip
        xchat.hook_print('Join', bcgeoip.join_location_check)
        return 0
    def bcbailiff_load():
        '''
        Module loading procedure.
        '''
        import bcbailiff
        xchat.hook_print('Channel Message', bcbailiff.scan_text)
        return 0
    
    def bcclones_load():
        '''
        Module loading procedure.
        '''
        import bcclones
        xchat.hook_print('Join', bcclones.join_clone_check)
        xchat.hook_command('CLONES', bcclones.clone_detect)
        xchat.hook_command('CLONES2', bcclones.clone_detect2)
        return 0
    
    def bccorrector_load():
        '''
        Module loading procedure.
        '''
        import bccorrector
        xchat.hook_print('Channel Message', bccorrector.do_corrections, None, xchat.PRI_HIGHEST)
        return 0
    
    def bccorrector2_load():
        '''
        Module loading procedure.
        '''
        import bccorrector2
        xchat.hook_print('Channel Message', bccorrector2.correct_line, None, xchat.PRI_HIGHEST)
        return 0
    
    def bchighlight_load():
        '''
        Module loading procedure.
        '''
        import bchighlight
        xchat.hook_print('Channel Msg Hilight', bchighlight.handle_highlights)
        return 0
    
    def bcinvite_load():
        '''
        Module loading procedure.
        '''
        import bcinvite
        xchat.hook_print('Invited', bcinvite.invite_handle)
        return 0
    
    def bcnotify_load():
        '''
        Module loading procedure.
        '''
        if os.name == 'nt':
            xchat.prnt("\x02\x0305Loading libnotify support on a Windows computer is NOT sensible. Do NOT be surpised if this breaks.\x03\x02")
            xchat.prnt("\x02\x0305Read your config file and disable bcnotify.\x03\x02")
        
        import bcnotify
        xchat.hook_print('Channel Msg Hilight', bcnotify.ChannelMessageHighlight_handle)
        if (bcsettings.modules_to_load.count("bccorrector") == 0):
            xchat.hook_print('Channel Message', bcnotify.ChannelMessage_handle)
        xchat.hook_print('Channel Action Hilight', bcnotify.ChannelActionHighligh_handle)
        xchat.hook_print('Channel Action', bcnotify.ChannelAction_handle)
        xchat.hook_print('Invited', bcnotify.Invite_handle)
        xchat.hook_print('Private Message', bcnotify.PRIVMSG_handle)
        xchat.hook_print('Private Message to Dialog', bcnotify.PRIVMSG_handle)
        return 0
    
    def bcoperfunctions_load():
        '''
        Module loading procedure.
        '''
        import bcoperfunctions
        xchat.hook_command('SANICK', bcoperfunctions.sanick_replace)
        xchat.hook_command('SACYCLE', bcoperfunctions.sacycle_replace)
        xchat.hook_command('SAMOVE', bcoperfunctions.samove_replace)
        return 0
    
    def bcphrasebook_load():
        '''
        Module loading procedure.
        '''
        import bcphrasebook
        xchat.hook_command("NOASL", bcphrasebook.noasl)
        xchat.hook_command("ASL", bcphrasebook.noasl)
        xchat.hook_command("NODATING", bcphrasebook.nodating)
        xchat.hook_command("DATING", bcphrasebook.nodating)
        xchat.hook_command("ENGLISH", bcphrasebook.english)
        xchat.hook_command("PCUSERS", bcphrasebook.pcusers)
        return 0
    
    def bcpurser_load():
        '''
        Module loading procedure.
        '''
        import bcpurser
        xchat.hook_print('Join', bcpurser.auto_give_privilage)
        return 0
    
    def bcregexpban_load():
        '''
        Module loading procedure.
        '''
        import bcregexpban
        xchat.hook_print('Join', bcregexpban.on_join_regexp_ban)
        xchat.hook_command('ADDREGEXP', bcregexpban.add_regexp)
        xchat.hook_command('REGEXP', bcregexpban.regexp_ban_check)
        return 0
    
    def bcroam_load():
        '''
        Module loading procedure.
        '''
        import bcroam
        xchat.hook_command('SAY', bcroam.msg_timer)
        xchat.hook_command('ME', bcroam.msg_timer)
        xchat.hook_command('NOTICE', bcroam.msg_timer)
        xchat.hook_command('', bcroam.msg_timer)
        xchat.hook_command('MSG', bcroam.msg_timer)
        xchat.hook_print('Channel Message', bcroam.away_check)
        return 0
    
    def bcenpea_load():
        '''
        Module Loading procedure.
        '''
        import bcenpea
        if os.name == 'nt' and (bcsettings.players.count("amarok") > 0 or bcsettings.players.count("exaile") > 0 or bcsettings.players.count("rhythmbox") > 0 ):
            xchat.prnt("\x02\x0305It would seem you want to load support for Linux media players on a Windows machine, this does not look like a good idea. Please read bcsettings.py and PLATFORM.\x03\x02")
        xchat.hook_command("NP", bcenpea.now_playing)
        xchat.hook_command("AMAROK", bcenpea.amarok)
        xchat.hook_command("EXAILE", bcenpea.exaile)
        xchat.hook_command("RHYTHMBOX", bcenpea.rhythmbox)
    #The guts of loading...
    for w in bcsettings.modules_to_load:
        exec(w + "_load()") #IGNORE:W0122
    
    def bcinfo(word, word_eol, userdata): #IGNORE:W0613
        '''
        Information about various things.
        @param word: all the data you need to work with, chopped up into small parts.
        @type word: string
        @param word_eol: all the data you need to work with, chopped from wherever you're starting from.
        @type word_eol: string
        @param userdata: custom object to pass back.
        @type userdata: object
        '''
        modules_info = {
            'bcroam': "This module allows you to 'roam' away from your pc, and let it automatically set you to being away. It allows you to set the timeout from your last text and the away message. Now supports auto returning.",
            'bcpurser': "This is a module to give out privilages, it will give out +o or +v to everyone who joins a room if you ask it to.",
            'bchighlight': "This module is designed to deal with repeat highlights, it can respond to or ban an offending user.",
            'bcoperfunctions': "This module supplies some 'extra' oper functions, like /sacycle and /samove.",
            'bccorrector': "A module designed to correct peoples 401 (AOL) speech impediments.",
            'bcinvite': "An auto respond to invite module, quite configurable.",
            'bcclones': "This module enables you to detect when clones join.",
            'bcphrasebook': "This module contains basic phrases to deal with users who are new.",
            'bcnotify': "A module designed to bring libnotify over to xchat, it is configurable so you can choose what to have pop up, and what not",
            'bcregexpban': "Detects regexp bans on join.",
            'bcbailiff': "Deals with annoying things you don't want to.",
            'bcsettings': "A module containing most of the external settings for the script(s)",
            'bcmisc': "A module containing a lot of data that BottleCap uses for it's actions.",
            'loaded': "BottleCap has loaded with the following modules: " + string.join(bcsettings.modules_to_load, ", "),
            'skipped': "BottleCap skipped loading these modules: " + skipped_modules()
        }
        
        if (len(word) == 1):
            xchat.prnt('This command lets you see information on modules, use `/BCINFO <modname>`. Use `/BCINFO loaded` to get a list of loaded modules, or skipped to get a list of skipped ones.')
        elif ((word[1].lower() in modules_info) == True):
            xchat.prnt(word[1].lower() + ": " + modules_info[word[1].lower()])
        elif (word[1].lower() == "reload"):
            xchat.prnt('Reloading BottleCap in one second...')
            xchat.command("TIMER 1 PY reload bottlecap")
        elif (word[1].lower() == "update"):
            xchat.prnt('Checking BottleCap\'s version...')
            http_version_thread().start()
        else:
            xchat.prnt('Unknown request. Use `/BCINFO loaded` to get a list of loaded modules, or skipped to get a list of skipped ones.')
        return xchat.EAT_ALL
    
    def version_response(word, word_eol, userdata): #IGNORE:W0613
        '''
        Respond to a version request.
        @param word: all the data you need to work with, chopped up into small parts.
        @type word: string
        @param word_eol: all the data you need to work with, chopped from wherever you're starting from.
        @type word_eol: string
        @param userdata: custom object to pass back.
        @type userdata: object
        '''
        if (word[0] == "VERSION"):
            if (xchat.get_prefs("irc_hide_version") == 1):
                xchat.command('nctcp ' + word[1] + ' VERSION XChat ' + xchat.get_info('version') + ' on ' + platform.platform().replace("-", " ") + '. XChat has loaded ' + __module_name__ + ' ' + compute_version() + ': ' + __module_description__)
            else:
                # xchat does not eat all, in fact, it sends both responses :x
                xchat.command('nctcp ' + word[1] + ' VERSION XChat has loaded ' + __module_name__ + ' ' + compute_version() + ': ' + __module_description__)
            
            return xchat.EAT_NONE
    
    def compute_version():
        '''
        Work out what the version should be.
        '''
        if __module_release__[:2] == "rc":
            temp = __module_version__ + "-" + __module_release__
        else:
            temp = __module_version__ + " " + __module_release__
        return temp
    
    class http_version_thread(threading.Thread):
        '''
        The version thread.
        '''
        def run(self):
            '''
            Called by .start()
            '''
            url = 'http://www.v8d.org/bottlecap_version.php'
            values = {'name': __module_name__,                      #Name of the module (generally BottleCap)
                      'version': __module_version__,                #Version
                      'release': __module_release__,                #Release
                      'platform': os.name,                          #A little platform information (posix or nt mostly)
                      'xchat': xchat.get_info('version'),           #Which version of xchat?
                      'nickname': bcsettings.pd_nickname,           #A nickname supplied by the user 
                      'district': bcsettings.pd_district,           #Their district if they set it. 
                      'country': bcsettings.pd_country,             #Their country if they set it.
                      'hostname': bcsettings.pd_hostname,           #Their hostname if they set it.
                      'extplatform': bcsettings.pd_extplatform      #An extended platform information, if set.
                      }
            data = urllib.urlencode(values)
            request = urllib2.Request(url, data)
            #try:
            getpage = urllib2.urlopen(request)
            the_page = getpage.read()
            xchat.prnt(the_page)
            #except:
            #    xchat.prnt("HTTP version test failed.")
            return 0
    def http_version_check():
        '''
        Checks version using http.
        '''
        url = 'http://www.v8d.org/bottlecap/bottlecap_version.php'
        values = {'name': __module_name__,                      #Name of the module (generally BottleCap)
                  'version': __module_version__,                #Version
                  'release': __module_release__,                #Release
                  'platform': os.name,                          #A little platform information (posix or nt mostly)
                  'xchat': xchat.get_info('version'),           #Which version of xchat?
                  'nickname': bcsettings.pd_nickname,           #A nickname supplied by the user 
                  'district': bcsettings.pd_district,           #Their district if they set it. 
                  'country': bcsettings.pd_country,             #Their country if they set it.
                  'hostname': bcsettings.pd_hostname,           #Their hostname if they set it.
                  'extplatform': bcsettings.pd_extplatform      #An extended platform information, if set.
                  }
        data = urllib.urlencode(values)
        request = urllib2.Request(url, data)
        getpage = urllib2.urlopen(request)
        the_page = getpage.read()
        xchat.prnt(the_page)
        return 0
    
    def skipped_modules():
        '''
        Tells you which modules were there but skipped!
        '''
        return "Sorry, this cannot be used at the moment, there seems to be some error in python, xchat's use of it, or my code."
#        d = os.listdir(os.path.dirname(__file__) + os.sep + "bottlecap")
#        
#        d = [x[:-3] for x in d if x.endswith(".py")]
#        d = [x for x in d if bcsettings.modules_to_load.count(x) == 0]
#        
#        return string.join(d, ", ")
    
    xchat.hook_command('BCINFO', bcinfo)
    xchat.hook_command('BC', bcinfo)
    
    xchat.hook_print('CTCP Generic', version_response)
    
    xchat.prnt('BottleCap ' + compute_version() + ' loaded...')
    xchat.prnt('BottleCap has loaded with the following modules: ' + string.join(bcsettings.modules_to_load, ", "))
    xchat.prnt('BottleCap skipped loading these modules: ' + skipped_modules())
    xchat.prnt('Please use /BCINFO for more info on what was loaded and what was not.')
    if (string.join(bcsettings.modules_to_load, ", ") == ""):
        xchat.prnt('BottleCap has been loaded with NO modules, this will mean you can see this, get the info and almost nothing else. Edit the config to change this.')
    
    if (xchat.get_prefs("irc_hide_version") == 0):
        xchat.prnt('\x0305(WARNING) It is advised that you do `/set irc_hide_version 1` to put your version response down to one line.\x03')
    xchat.prnt('\x02It is advised that you idle on the channel #BottleCap on irc.v8d.org because this is the place that there will be any warnings about exploits or notifications of updates.\x02')
    
    if (os.name == 'nt'):
        http_version_check()
    else:
        http_version_thread().start()